﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EzDesk.Core.Model;
using EzDesk.Utility;
using EzDesk.Utility.EzML;
using EzDesk.Core.CoreImpl.Filters;
using EzDesk.Core.CoreImpl.Services;

namespace EzDesk.Core.CoreImpl
{
    public partial class CoreService : ICoreService
    {
        #region [ Send Feeds Methods ] 
        Guid ICoreService.SendFeed(string feedTypeStr, string templateName, Guid? senderId, string feedData, string memberString, DateTime expireOn, bool sendToSelf)
        {
            // 消息模板
            var template = _feedTemplateRepository.GetAll().Where(p => p.TemplateName == templateName).SingleOrDefault();
            if (template == null)
            {
                throw new Exception("Feed Template not Found!");
            }

            return innerSendFeed(feedTypeStr, template, senderId, feedData, memberString, sendToSelf);
        }

        Guid ICoreService.SendFeed(string feedTypeStr, Guid templateId, Guid? senderId, string feedData, string memberString, DateTime expireOn, bool sendToSelf)
        {
            // 消息模板
            var template = _feedTemplateRepository.GetById(templateId);
            if (template == null)
            {
                throw new Exception("Feed Template not Found!");
            }

            return innerSendFeed(feedTypeStr, template, senderId, feedData, memberString, sendToSelf);
        }

        private Guid innerSendFeed(string feedTypeStr, FeedTemplate template, Guid? senderId, string feedData, string memberString, bool sendToSelf)
        {
            Guid templateId = template.Id;
            int feedType = FeedTypeDictionary.StringToIntType(feedTypeStr);

            if (template.Type != feedType)
            {
                throw new Exception("FeedType doesn't match!");
            }

            if (feedType < -1)
            {
                throw new Exception("Feed Type Error!");
            }

            // 验证FeedData和模板的匹配
            try
            {
                validateFeedData(template, feedData);
            }
            catch (Exception ex)
            {
                throw new Exception("FeedData Error!", ex);
            }

            Guid feedId = Guid.NewGuid();

            // 创建 Feed
            Feed feed = new Feed()
            {
                Id = feedId,
                TemplateId = templateId,
                CreateOn = DateTime.Now,
                UpdateOn = DateTime.Now,
                ExpireOn = DateTime.Now.AddDays(2), /* todo: update 过期时间 */
                FeedData = feedData,
                IsRead = false,
                IsAvailable = true,
                OwnUserId = senderId,
                FeedType = feedType,
            };
            _feedRepository.Add(feed, false);

            // 发送给的人
            IList<Guid> usersIdsToSend = getAllUserIdsByMemberString(memberString, senderId, sendToSelf);

            foreach (var userId in usersIdsToSend)
            {
                _feedRepository.AddUserToFeed(userId, feedId, null);
            }
            _feedRepository.SaveChanges();

            return feedId;
        }

        private void validateFeedData(FeedTemplate template, string feedData)
        {
            EzMLHelper.MergeDataToEzML(template.Title, feedData);
            EzMLHelper.MergeDataToEzML(template.Body, feedData);
        }


        void ICoreService.UpdatePersonalFeedData(Guid feedId, string memberstring, string feedDataEx)
        {
            var userIds = self.GetAllUserIdsByMemberString(memberstring);
            foreach(var userId in userIds)
            {
                // 合并FeedData
                string originalData = _feedRepository.GetPersonalFeedData(userId, feedId);
                var feedDataToUpdate = merageExtraFeedData(originalData, feedDataEx);
                if (feedDataToUpdate != originalData)
                {
                    _feedRepository.UpdatePersonalFeedData(userId, feedId, feedDataToUpdate, false);
                }
            }
            _feedRepository.SaveChanges();
        }



        #endregion

        #region [ Set Feed Properties Methods ]

        void ICoreService.SetFeedIsRead(Guid feedId, string memberString, bool isRead)
        {
            self.SetFeedIsRead(
                convertSingleIdToIdCollection(feedId),
                memberString,
                isRead);
        }
        void ICoreService.SetFeedIsRead(string feedIdStrs, string memberString, bool isRead)
        {
            self.SetFeedIsRead(
                convertIdStrsToIdCollection(feedIdStrs),
                memberString,
                isRead
                );
        }

        void ICoreService.SetFeedIsRead(Guid[] feedIds, string memberString, bool isRead)
        {
            var userIds = self.GetAllUserIdsByMemberString(memberString);
            foreach (var feedId in feedIds)
            {
                foreach (var userId in userIds)
                {
                    _feedRepository.SetIsRead(feedId, userId, isRead, false);
                }
            }
            _feedRepository.SaveChanges();
        }


        void ICoreService.SetFeedIsAvailable(Guid feedId, string memberString, bool isAvailable)
        {
            self.SetFeedIsAvailable(
                convertSingleIdToIdCollection(feedId),
                memberString,
                isAvailable
                );
        }


        void ICoreService.SetFeedIsAvailable(string feedIdStrs, string memberString, bool isAvailable)
        {
            self.SetFeedIsAvailable(
                convertIdStrsToIdCollection(feedIdStrs),
                memberString,
                isAvailable
                );
        }

        void ICoreService.SetFeedIsAvailable(Guid[] feedIds, string memberString, bool isAvailable)
        {
            var userIds = self.GetAllUserIdsByMemberString(memberString);
            foreach (var feedId in feedIds)
            {
                foreach (var userId in userIds)
                {
                    _feedRepository.SetIsAvailable(feedId, userId, isAvailable, false);
                }
            }
            _feedRepository.SaveChanges();
        }


        #endregion

        #region [ Update Feeds Methods]

        void ICoreService.UpdateFeedData(Guid feedId, string newFeedData)
        {
            self.UpdateFeedData(
                convertSingleIdToIdCollection(feedId),
                newFeedData
                );
        }

        void ICoreService.UpdateFeedData(string feedIdStrs, string newFeedData)
        {
            self.UpdateFeedData(
                convertIdStrsToIdCollection(feedIdStrs),
                newFeedData
                );
        }

        void ICoreService.UpdateFeedData(Guid[] feedIds, string newFeedData)
        {
            foreach (var feedId in feedIds)
            {
                Feed feed = _feedRepository.GetById(feedId);
                FeedTemplate feedTemplate = _feedTemplateRepository.GetById(feed.TemplateId);
                if (feed != null)
                {
                    string newFeedDataToUpdate = merageNewFeedData(feed.FeedData, newFeedData);
                    validateFeedData(feedTemplate, newFeedDataToUpdate);
                    feed.FeedData = newFeedDataToUpdate;
                    feed.UpdateOn = DateTime.Now;
                    feed.IsRead = false;
                    _feedRepository.Update(feed, false);
                    continue;
                }

                throw new Exception("Feed Not Found!");
            }
            _feedRepository.SaveChanges();
            return;
        }

        private string merageNewFeedData(string originalFeedData, string newFeedData)
        {
            IDictionary<string, string> orignalData = JsonHelper.JsonToDictionary(originalFeedData);
            IDictionary<string, string> newData = JsonHelper.JsonToDictionary(newFeedData);
            // 更新 原有字段信息
            foreach (var item in newData)
            {
                if (orignalData.ContainsKey(item.Key))
                {
                    orignalData[item.Key] = item.Value;
                }
                else
                {
                    //todo: error
                    throw new Exception("Feed Data Error! " + item.Key + " not found!");
                }
            }
            return JsonHelper.ConvertToJson(orignalData);
        }

        private string merageExtraFeedData(string originalFeedData, string newFeedData)
        {
            IDictionary<string, string> orignalData = JsonHelper.JsonToDictionary(originalFeedData);
            IDictionary<string, string> newData = JsonHelper.JsonToDictionary(newFeedData);

            foreach (var item in newData)
            {
                if (orignalData.ContainsKey(item.Key))
                {
                    orignalData[item.Key] = item.Value;
                }
                else
                {
                    orignalData.Add(item.Key, item.Value);
                }
            }
            return JsonHelper.ConvertToJson(orignalData);
        }
        #endregion

        #region [ Delete Methods ]
        void ICoreService.DeleteFeed(Guid feedId, int type)
        {
            Feed feed = _feedRepository.GetById(feedId);
            if (feed != null)
            {
                _feedRepository.Delete(feed.Id);
            }
            else
            {
                throw new Exception("Feed Not Found");
            }
            return;
        }
        #endregion

        
        #region [ Get Feeds ]

        IList<Feed> ICoreService.GetFeeds(string feedTypeStr, Guid userId, DateTime from, DateTime to, int maxCount, bool? isRead, bool? isAvaiable)
        {
            int feedType = FeedTypeDictionary.StringToIntType(feedTypeStr);

            if (feedType < -1)
            {
                throw new Exception("Feed Type Error!");
            }

            IQueryable<Feed> feeds = _feedRepository.GetByUser(userId, isRead, isAvaiable)
                .Where(p => p.FeedType == feedType);

            if (from > DateTime.MinValue)
            {
                feeds = feeds.Where(p => p.UpdateOn > from || p.LastChangeOn > from);
            }
            if (to < DateTime.MaxValue)
            {
                feeds = feeds.Where(p => p.UpdateOn < to || p.LastChangeOn < to);
            }

            feeds = feeds.OrderByDescending(p => p.UpdateOn);

            // 限量..
            feeds = feeds.Take(maxCount);

            return feeds.ToList();
        }

        IList<Feed> ICoreService.GetFeeds(string feedTypeStr, Guid userId, int startIndex, int count, bool? isRead, bool? isAvaiable)
        {
            int feedType = FeedTypeDictionary.StringToIntType(feedTypeStr);

            if (feedType < -1)
            {
                throw new Exception("Feed Type Error!");
            }

            IQueryable<Feed> feeds = _feedRepository.GetByUser(userId, isRead, isAvaiable)
                .Where(p => p.FeedType == feedType)
                .OrderByDescending(p => p.UpdateOn)
                .Skip(startIndex)
                .Take(count);

            return feeds.ToList();

        }

        #endregion


        string ICoreService.GetPersonalFeedData(Guid userId, Guid feedId)
        {
            return _feedRepository.GetPersonalFeedData(userId, feedId);
        }

        #region ICoreService Members



        #endregion
    }
}
